import json
import time

import requests

from logger import logger
from notice import DingDingRobot
from tencent_sdk import TencentApiTools
from tools import ConfigTools


secret_id, secret_key, access_token, kibana_version, kibana_ip\
    = ConfigTools().read_config("tencent.common.SecretId", "tencent.common.SecretKey", "dingding.robot.access_token",
                                "kibana.version", "kibana.ip")


def main():
    while True:
        logger.info("start searching kibana logs...")
        try:
            find_403_visitors()
        except Exception as e:
            logger.error(e)

        time.sleep(10 * 60)  # 10 minutes


def add_tencent_cdn_ips_to_nginx(ip_allows):
    with open("/opt/1-white-list.conf", 'r') as conf_file:
        old_configs = conf_file.readlines()
    with open("/opt/1-white-list.conf", 'w') as conf_file:
        now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        conf_file.write("# " + now + "\n")
        for ip in ip_allows:
            item = "allow " + ip + ";\n"
            if item in old_configs:
                logger.info(item + "is already in the config, passed.")
            else:
                conf_file.write(item)
        conf_file.writelines(old_configs)


def find_403_visitors():
    now = int(time.time()) * 1000
    thirty_minutes_ago = now - 1000 * 60 * 10  # 10 minutes
    # print(now)
    # print(thirty_minutes_ago)
    data = '{"index":"logstash_cdn_static*","ignore_unavailable":true}\n{"version":true,"size":500,"sort":[{"@timestamp":{"order":"desc","unmapped_type":"boolean"}}],"_source":{"excludes":[]},"aggs":{"2":{"date_histogram":{"field":"@timestamp","interval":"30s","time_zone":"Asia/Shanghai","min_doc_count":1}}},"stored_fields":["*"],"script_fields":{},"docvalue_fields":[{"field":"@timestamp","format":"date_time"}],"query":{"bool":{"must":[{"match_all":{}},{"match_phrase":{"status":{"query":"403"}}},{"range":{"@timestamp":{"gte":%(start)s,"lte":%(now)s,"format":"epoch_millis"}}}],"filter":[],"should":[],"must_not":[]}},"highlight":{"pre_tags":["@kibana-highlighted-field@"],"post_tags":["@/kibana-highlighted-field@"],"fields":{"*":{}},"fragment_size":2147483647},"timeout":"30000ms"}\n'
    data = data % dict(now=now, start=thirty_minutes_ago)

    url = "http://" + kibana_ip + "/elasticsearch/_msearch?rest_total_hits_as_int=true&ignore_throttled=true"

    header = {
        "Origin": "http://" + kibana_ip,
        "Content-Length": '862',
        "Accept-Language": "en,zh-CN;q=0.9,zh;q=0.8",
        "Accept-Encoding": "gzip, deflate",
        "kbn-version": kibana_version,
        "Connection": "keep-alive",
        "Accept": "application/json, text/plain, */*",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36",
        "Host": kibana_ip,
        "Referer": "http://" + kibana_ip + "/app/kibana",
        "content-type": "application/x-ndjson"
    }

    r = requests.post(url=url, headers=header, data=data)

    if r.status_code != 200:
        raise RuntimeError("error! request {} response code is ".format(url), r.status_code)

    r_text = r.text
    # print(r_text)
    result_json = json.loads(r_text)
    normal_ips = []
    if 'responses' in result_json and 'hits' in result_json['responses'][0]:
        total = result_json['responses'][0]['hits']['total']
        if total > 0:
            logger.info("{} 403 visitors hits from kibana.".format(total))
            log_list = result_json['responses'][0]['hits']['hits']
            for log in log_list:
                log_nginx = log['_source']['path']
                if '/img/' in log_nginx:
                    remote_addr = log['_source']['remote_addr']
                    if remote_addr not in normal_ips:
                        normal_ips.append(remote_addr)

            if len(normal_ips) > 0:
                logger.info("found {} normal_ips visitors from kibana log: ".format(len(normal_ips)))
                cdn_ips = TencentApiTools(secret_id, secret_key).describe_cdn_ip(normal_ips)

                if len(cdn_ips) > 0:
                    logger.info("found tencent cdn ips: {}".format(cdn_ips))
                    ip_allows = []
                    for ip in cdn_ips:
                        ip_items = ip.split('.')
                        ip_allow = '.'.join(ip_items[0:3]) + ".0/24"
                        if ip_allow not in ip_allows:
                            ip_allows.append(ip_allow)

                    DingDingRobot(access_token).make_text_msg("find new Tencent CDN IPs: \n" + str(ip_allows)).send()
                    add_tencent_cdn_ips_to_nginx(ip_allows)
                else:
                    logger.warning("found {} normal_ips visitors, but has no tencent CDN IPs".format(len(normal_ips)))
            else:
                logger.warning("not found normal_ips visitors from kibana log")

        else:
            logger.warning("not found 403 visitors form kibana's log")
    else:
        raise RuntimeError("error!, request kibana log returns 200 code, but not found response.", r_text)


if __name__ == '__main__':
    main()


